using System;
using System.Collections.Generic;
using System.Text;
using Xeml.Document.Contracts;
using Mpi.Common.Collections;
using System.Linq;

namespace Xeml.Document
{
    public static class DocumentHelper
    {

        public static IEnumerable<Sample> ExtractSamples(IDocument xemlDoc)
        {
            foreach (TreeNode<StoryBase> sbNode in xemlDoc.StoryBoard)
            {
                foreach (Sample item in sbNode.Content.Samples)
                {
                    yield return item;
                }
            }
            yield break;
        }

        public static StoryBase GetStoryBySampleId(this IDocument xemlDoc, int SampleId)
        {
            foreach (TreeNode<StoryBase> storynode in xemlDoc.StoryBoard)
            {
                if (storynode.Content.Samples.Contains(SampleId))
                {
                    return storynode.Content;
                }
            }
            return null;
        }

        //public static int NextPartitionId(StoryBase sb)
        //{
        //    int nextId = 1;
        //    foreach (ObservationPoint op in sb.ObservationPoints)
        //    {
        //        foreach (Observation o in op.Observations)
        //        {
        //            foreach (Partition p in o.Partitions)
        //            {
        //                nextId = Math.Max(p.Id, nextId + 1);
        //            }
        //        }
        //    }
        //    return nextId;
        //}

        /// <summary>
        /// Calculates the next valuable observation id.
        /// </summary>
        /// <returns>The calculated id.</returns>
        public static int NextObservationId(StoryBoard sb)
        {
            int x = 0;
            foreach (TreeNode<StoryBase> node in sb)
            {
                foreach (ObservationPoint op in node.Content.ObservationPoints)
                {
                    x = Math.Max(op.Id, x);
                }
            }
            return x + 1;
        }

        public static int IndexOf(ObservationPoint op)
        {

            StoryBoard sb = op.Collection.Story.StoryBoard;
            List<ObservationPoint> obPoints = GetAllObPoints(sb);
            long ticks;
            SortedDictionary<long, SortedDictionary<int, List<ObservationPoint>>> dict = new SortedDictionary<long, SortedDictionary<int, List<ObservationPoint>>>();
            foreach (var item in obPoints)
            {
                ticks = item.TimePoint.Ticks;
                int sbIndx = sb.IndexOf(op.Collection.Story);
                if (!dict.ContainsKey(ticks))
                    dict.Add(ticks, new SortedDictionary<int, List<ObservationPoint>>());
                if (!dict[ticks].ContainsKey(sbIndx))
                    dict[ticks].Add(sbIndx, new List<ObservationPoint>());
                dict[ticks][sbIndx].Add(item);

            }

            int indx = 1;
            foreach (var t in dict.Keys)
            {
                foreach (var sbi in dict[t].Keys)
                {
                    for (int i = 0; i < dict[t][sbi].Count; i++)
                    {
                        if (dict[t][sbi][i] == op)
                            return indx;
                        else
                            indx++;
                    }
                }
            }

            return -1;
        }

        private static List<ObservationPoint> GetAllObPoints(StoryBoard sb)
        {
            List<ObservationPoint> ret = new List<ObservationPoint>();
            foreach (TreeNode<StoryBase> item in sb)
            {
                ret.AddRange(item.Content.ObservationPoints);
            }
            return ret;
        }

        public static IEnumerable<Sample> FindAllSamples(ObservationPoint op)
        {
            StoryBase sb = op.Collection.Story;
            if (sb != null)
            {
                bool isConsumer = false;
                foreach (Sample s in sb.Samples)
                {
                    isConsumer = false;
                    foreach (Observation o in op.Observations)
                    {
                        foreach (Partition p in o.Partitions)
                        {
                            if (s.Partitions.Contains(p))
                            {
                                isConsumer = true;
                                break;
                            }
                        }
                        if (isConsumer)
                            break;
                    }
                    if (isConsumer)
                        yield return s;
                }
            }
        }

        public static void ClearAllSampling(IDocument xemlDoc)
        {
            if (xemlDoc != null)
            {
                foreach (TreeNode<StoryBase> node in xemlDoc.StoryBoard)
                {
                    //node.Content.Samples.Clear();
                    //node.Content.ObservationPoints.Clear();

                    foreach (ObservationPoint op in node.Content.ObservationPoints)
                    {
                        ClearRelatedSampling(op);
                    }
                    if (node.Content is Story)
                    {
                        foreach (IndividualsPool ip in (node.Content as Story).Pools)
                        {
                            ip.Individuals.Clear();
                        }
                    }
                }
            }
        }

        public static void ClearRelatedSampling(ObservationPoint op)
        {
            if (op != null)
            {
                List<Sample> samples = DocumentHelper.FindAllSamples(op).ToList();
                List<Observation> obs = new List<Observation>();
                foreach (Sample s in samples)
                {
                    foreach (Partition p in s.Partitions)
                    {
                        Observation o = p.Collection.Observation;
                        if (!obs.Contains(o))
                            obs.Add(o);
                        p.Collection.Remove(p);// = null; //Removes p from its Collection
                        p.Material.Clear();
                    }
                    s.Collection.Remove(s);// = null;
                }
                foreach (Observation o in obs)
                {
                    if (o.Partitions.Count == 0)
                    {
                        if (o.Individual != null)
                            o.Individual.Collection.Remove(o.Individual);// = null;
                        o.Collection.Remove(o);// = null;
                    }
                }
            }
        }

        public static string ResolveNameSpaceToAlias(IEnumerable<OntologyHandlerResource> ontologies, string nameSpace)
        {
            foreach (OntologyHandlerResource ohr in ontologies)
            {
                if (ohr.ComponentState == ComponentLoadState.Loaded && ohr.Handler.NameSpace == nameSpace)
                {
                    return ohr.NameSpaceAlias;
                }

            }
            return null;
        }

        public static string ResolveAliasToNameSpace(IEnumerable<OntologyHandlerResource> ontologies, string alias)
        {
            foreach (OntologyHandlerResource ohr in ontologies)
            {
                if (ohr.ComponentState == ComponentLoadState.Loaded && ohr.NameSpaceAlias == alias)
                {
                    return ohr.Handler.NameSpace;
                }

            }
            return null;
        }

        public static IEnumerable<TimeSpan> TimePointsOfAltering(StoryBoard sb, TimeSpan start)
        {
            List<TimeSpan> ret = new List<TimeSpan>();
            foreach (TreeNode<StoryBase> tns in sb)
            {
                foreach (TimeSpan ts in tns.Content.HistoryTimePoints(false))
                {
                    if (ts >= start && !ret.Contains(ts))
                    {
                        ret.Add(ts);
                        yield return ts;
                    }
                }
            }
        }

        public static Sample GetSample(this IDocument doc, int targetSampleId)
        {
            return ExtractSamples(doc).Single(x => x.Id == targetSampleId);
        }

        public static string GetMaterialDescription(this Sample s)
        {
            return string.Join("; ", s.Partitions.Select(x => string.Join("; ", x.Material.Select(y => y.Name).Distinct())).Distinct());
        }

        public static string GetDevelopmentalStageDescription(this Sample s)
        {
            return string.Join("; ", s.Partitions.Select(p => p.Collection.Observation.DevelopmentalStages.Select(d => d.Name)).Flatten().Distinct());
        }

        public static string GetGermDescription(this Sample s)
        {
            return string.Join("; ", s.Partitions.Select(p => p.Collection.Observation.IndividualsPool.GermPlasm).Distinct());
        }
        
        public static IEnumerable<string> Flatten(this IEnumerable<IEnumerable<string>> input)
        {
            foreach (IEnumerable<string> item1 in input)
            {
                foreach (string item2 in item1)
                {
                    yield return item2;
                }
            }
            yield break;
        }
    }
}
